package com.truth.lock.configure.zookeeper;

import com.truth.lock.configure.TruthLockProperties;
import com.truth.lock.executor.TruthLockExecutor;
import com.truth.lock.executor.zookeeper.ZookeeperMutexLockExecutor;
import com.truth.lock.executor.zookeeper.ZookeeperReadLockExecutor;
import com.truth.lock.executor.zookeeper.ZookeeperWriteLockExecutor;
import org.apache.curator.RetryPolicy;
import org.apache.curator.framework.CuratorFramework;
import org.apache.curator.framework.CuratorFrameworkFactory;
import org.apache.curator.framework.recipes.locks.InterProcessMutex;
import org.apache.curator.framework.recipes.locks.InterProcessReadWriteLock;
import org.apache.curator.retry.ExponentialBackoffRetry;
import org.springframework.boot.autoconfigure.condition.ConditionalOnBean;
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

/**
 * @author truth
 */
@Configuration
@EnableConfigurationProperties(TruthLockProperties.class)
@ConditionalOnClass(name = {"org.apache.curator.framework.CuratorFramework"})
@ConditionalOnProperty(prefix = "truth.lock", name = "lock-type", havingValue = "zookeeper")
public class ZookeeperAutoConfiguration {

    @Bean(initMethod = "start", destroyMethod = "close")
    @ConditionalOnMissingBean(type = {"org.apache.curator.framework.CuratorFramework"})
    public CuratorFramework curatorFramework(TruthLockProperties properties) {
        ZookeeperProperties zookeeper = properties.getZookeeper();
        RetryPolicy retryPolicy = new ExponentialBackoffRetry(zookeeper.getBaseSleepTimeMs()
                , zookeeper.getMaxRetries());
        return CuratorFrameworkFactory.builder()
                .connectString(zookeeper.getZkServers())
                .sessionTimeoutMs(zookeeper.getSessionTimeout())
                .connectionTimeoutMs(zookeeper.getConnectionTimeout())
                .retryPolicy(retryPolicy)
                .build();
    }

    @Bean
    @ConditionalOnBean(type = {"org.apache.curator.framework.CuratorFramework"})
    public TruthLockExecutor<InterProcessMutex> zookeeperMutexLockExecutor(CuratorFramework curatorFramework) {
        return new ZookeeperMutexLockExecutor(curatorFramework);
    }

    @Bean
    @ConditionalOnBean(type = {"org.apache.curator.framework.CuratorFramework"})
    public TruthLockExecutor<InterProcessReadWriteLock.WriteLock> zookeeperWriteLockExecutor(CuratorFramework curatorFramework) {
        return new ZookeeperWriteLockExecutor(curatorFramework);
    }

    @Bean
    @ConditionalOnBean(type = {"org.apache.curator.framework.CuratorFramework"})
    public TruthLockExecutor<InterProcessReadWriteLock.ReadLock> zookeeperReadLockExecutor(CuratorFramework curatorFramework) {
        return new ZookeeperReadLockExecutor(curatorFramework);
    }

}
